package com.wyg.lambda.streamapi.operate;

import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.ToIntFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Stream API Demo
 *
 * 二、Stream 操作
 *
 *      1.中间操作方法：
 *          过滤 filter()
 *          去重 distinct()
 *          排序 sorted()
 *          截取 limit()、skip()
 *          转换 map()/flatMap()
 *          其他 peek()
 *
 *      2.终止操作方法：
 *          循环 forEach()
 *          计算 min()、max()、count()、average()
 *          匹配 anyMatch()、allMatch()、noneMatch()、findFirst()、findAny()
 *          汇聚 reduce()
 *          收集器 toArray()、collect()
 *
 * @ClassName: StreamOperate
 * @Auther: WangYG
 * @Date: 2020-02-22 19:51:34
 * @Version: 1.0
 */
public class StreamOperate {

    private final static Integer[] NUM_ARRAY = {1,2,3,4,5,6};
    private final static String[] STRINGS_ARRAY = {"hello","hi","A","lambda","java"};

    /**
     * 功能描述: StreamAPI-filter()演示
     * 功能：过滤集合元素
     * <P>
     *     Stream<T> filter(Predicate<? super T> predicate);
     *          ---public interface Predicate<T>
     *                  ---boolean test(T t);
     * </P>
     * @methodName: one
     * @params: []
     * @return: void
     * @exception:
     * @auther: WangYG
     * @date: 2020-02-22 21:44:41
     */
    public void one(){

        //1.普通方式输入-全内部结构方法
        Stream<Integer> stream = Stream.of(NUM_ARRAY);
        //public interface Predicate<T> -> boolean test(T t)
        Stream<Integer> stream1 = stream.filter(new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                return integer % 2 == 0;
            }
        });
        stream1.forEach(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.println("普通方式：Stream.filter过滤后，forEach输出结果 integer ："+integer);
            }
        });

        //2.使用Lambda表达式-省略缩写演示-链式调用
        //将数组转为Stream
        Stream.of(NUM_ARRAY)
                //使用中间操作方法filter(Predicate->test(T))过滤属性值
                .filter((x) -> x%2==0)
                //将过滤好的属性值通过终止操作方法遍历输出，使用方法引用格式书写
                .forEach(System.out::println);
    }

    /**
     * 功能描述: StreamAPI- filter()、mapToInt()、IntStream.sum()演示
     *
     * <P>
     *     1.filter()
     *          Stream<T> filter(Predicate<? super T> predicate);
     *                  ---public interface Predicate<T>
     *                          ---boolean test(T t);
     *     2.mapToInt()
     *          IntStream mapToInt(ToIntFunction<? super T> mapper);
     *                  ---public interface ToIntFunction<T>
     *                          ---int applyAsInt(T value);
     *
     *     3.sum()
     *          IntStream -- int sum()
     *
     *     4.链式调用
     *
     *          Stream.of().filter().mapToInt().sum()
     *
     * </P>
     *
     * @methodName: two
     * @params: []
     * @return: void
     * @exception:
     * @auther: WangYG
     * @date: 2020-02-22 22:57:26
     */
    public void two(){

        //1.普通方式输入-全内部结构方法
        Stream<Integer> stream = Stream.of(NUM_ARRAY);
        //stream.filter过滤  保留集合中%2==0的元素
        Stream<Integer> stream1 = stream.filter(new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                return integer % 2 == 0;
            }
        });
        //stream.mapToInt将集合中元素转换为Int，返回的是IntStream类型
        //IntStream mapToInt(ToIntFunction<? super T> mapper)
        //public interface ToIntFunction<T> -> int applyAsInt(T value)
        int sum = stream1.mapToInt(new ToIntFunction<Integer>() {
            @Override
            public int applyAsInt(Integer value) {
                return value;
            }
            //使用IntStream.sum()方法，求集合中所有元素的和。
        }).sum();
        System.out.println("普通方式：Stream.filter过滤后，mapToInt将集合中元素转换为Int返回IntStream，然后在调用IntStream.sum()求和 sum ："+sum);

        //2.使用Lambda表达式-省略缩写演示-链式调用
        //Stream.of将数组转为Stream
        int sum1 = Stream.of(NUM_ARRAY)
                //Stream.filter过滤集合元素
                .filter(x -> x % 2 == 0)
                //Stream.mapToInt将集合中的元素转换为int型，返回的是IntStream
                .mapToInt(x -> x)
                //IntStream.sum 集合元素求和
                .sum();
        System.out.println("Lambda链式调用方式：Stream.of().filter().mapToInt().sum() -> sum ："+sum);

    }

    /**
     * 功能描述: StreamAPI- 演示
     *              filter()、过滤
     *              max()、最大值
     *              min()、最小值
     *              Optional<T>.get() 获取结果
     *
     * <P>
     *     1.filter()
     *          Stream<T> filter(Predicate<? super T> predicate);
     *                  ---public interface Predicate<T>
     *                          ---boolean test(T t);
     *     2.max() 、 min()
     *          Optional<T> max(Comparator<? super T> comparator);
     *          Optional<T> min(Comparator<? super T> comparator);
     *
     *                  ---public interface Comparator<T>
     *                          ---int compare(T o1, T o2);
     *
     *     3.get()
     *          Optional<T> -- public T get()
     *
     *     4.链式调用
     *
     *          Stream.of().max().get()
     *          Stream.of().min().get()
     *
     * </P>
     * @methodName: three
     * @params: []
     * @return: void
     * @exception:
     * @auther: WangYG
     * @date: 2020-02-22 23:20:00
     */
    public void three(){

        //1.普通方式输入-全内部结构方法
        //Stream.of转换为stream
        Stream<Integer> stream = Stream.of(NUM_ARRAY);
        //stream.max() 求集合中的最大值
        //Optional<T> max(Comparator<? super T> comparator)
        //public interface Comparator<T> -> int compare(T o1, T o2);
        Optional<Integer> maxOpt = stream.max(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;
            }
        });
        //Optional.get()获取结果
        Integer max = maxOpt.get();
        System.out.println("普通方式：Stream.filter过滤后，stream.max比较最大值，然后在调用Optional.get()获取最大值 max ：" + max);

        //2.使用Lambda表达式-省略缩写演示-链式调用
        //Stream.of()将数组转为Stream
        Integer max1 = Stream.of(NUM_ARRAY)
                //stream.max()求集合中的最大值，传入比较器Comparator<>,返回Optional<T>
                //比较器中a-b大于0的返回
                .max((a, b) -> a - b)
                //Optional<T>.get()获取结果
                .get();
        System.out.println("Lambda链式调用方式：Stream.of().max().get() -> max1 ：" + max1);

        //同理min()方法也一样
        //Stream.of()将数组转为Stream
        Integer min = Stream.of(NUM_ARRAY)
                //stream.min()求集合中的最小值，传入比较器Comparator<>,返回Optional<T>
                //比较器中a-b小于0的返回
                .min((a, b) -> a - b)
                //Optional<T>.get()获取结果
                .get();
        System.out.println("Lambda链式调用方式：Stream.of().min().get() -> min ：" + min);
        long count = Stream.of(NUM_ARRAY).count();
        System.out.println("Lambda链式调用方式：Stream.of(NUM_ARRAY).count();-> count ：" + count);

    }

    /**
     * 功能描述: 功能描述: StreamAPI- filter()、findAny()、findFirst()、sorted()、Optional<T>.get()演示
     * @methodName: four
     * @params: []
     * @return: void
     * @exception:
     * @auther: WangYG
     * @date: 2020-02-22 23:44:54
     */
    public void four(){

        //1.普通方式输入-全内部结构方法
        //Stream.of转换为stream
        Stream<Integer> stream = Stream.of(NUM_ARRAY);
        //stream.filter过滤  保留集合中%3==0的元素
        Stream<Integer> stream1 = stream.filter(new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                return integer % 3 == 0;
            }
        });
        //stream.findAny() 集合中的任何一个
        //Optional<T> findAny()
        Optional<Integer> anyOpt = stream1.findAny();
        //Optional<T> -> public T get()
        Integer any = anyOpt.get();
        System.out.println("普通方式：Stream.filter过滤后，stream.findAny集合中的任何一个，然后在调用Optional.get()获取结果 any ：" + any);

        //2.使用Lambda表达式-省略缩写演示-链式调用

        Integer any1 = Stream.of(NUM_ARRAY).filter(x -> x % 3 == 0).findAny().get();
        Integer first = Stream.of(NUM_ARRAY).filter(x -> x % 3 == 0).findFirst().get();
        //比较函数sorted()  Stream<T> sorted(Comparator<? super T> comparator)
        //sorted((a,b) -> b-a) a-b大于0那就是正序， b-a如果大于0那就是倒序
        Integer orderByFirst = Stream.of(NUM_ARRAY).filter(x -> x % 3 == 0).sorted((a,b) -> b-a).findFirst().get();
        System.out.println("any1 : " + any1);
        System.out.println("first : " + first);
        System.out.println("orderByFirst : " + orderByFirst);

    }

    /**
     * 功能描述: StreamAPI- 排序sorted()、sorted(Comparator<? super T> comparator)演示
     * @methodName: five
     * @params: []
     * @return: void
     * @exception:
     * @auther: WangYG
     * @date: 2020-02-22 23:51:01
     */
    public void five(){
        //sorted(Comparator<? super T> comparator)
        //sorted((a,b) -> a.length() - b.length()) a-b大于零正序，b-a大于零倒序
        Stream.of(STRINGS_ARRAY).sorted((a,b) -> a.length() - b.length()).forEach(x -> System.out.println(x));
        Stream.of(STRINGS_ARRAY).sorted((a,b) -> b.length() - a.length()).forEach(System.out::println);
    }

    /**
     * 功能描述: StreamAPI- 演示
     *              iterate() 迭代器-无限循环
     *              limit() 设置执行次数，上限。
     *              filter()、集合过滤
     *              collect()、收集为集合
     *              Collectors.toList()、生成一个List集合
     *              forEach() 遍历集合
     *
     * @methodName: six
     * @params: []
     * @return: void
     * @exception:
     * @auther: WangYG
     * @date: 2020-02-23 00:19:26
     */
    public void six(){

        //找出1-50之内的所有偶数
        //1.使用Stream.iterate无限循环遍历，初始值=1，x自动循环x+1,并将x+1的结果，再次赋值给x进行循环。无限递增
        Stream.iterate(1, x -> x + 1)
                //Stream.limit 表示循环上限为50次，到50次结束
                .limit(50)
                //Stream.filter 筛选出Stream集合中元素为偶数的
                .filter(x -> x % 2 == 0)
                //Stream.collect收集器，将元素中的集合收集为List,
                // 由于collect(Collector)参数为Collector自定义不好实现，直接使用Collectors.toList()生成一个List.
                //<R, A> R collect(Collector<? super T, A, R> collector);
                .collect(Collectors.toList())
                //将本次结果List<Integer>使用forEach遍历
                .forEach(System.out::println);

        Object[] singleArray = Stream.iterate(1, x -> x + 1)
                .limit(50)
                .filter(x -> x % 2 != 0)
                .toArray();
        Stream.of(singleArray).forEach(System.out::println);

    }

    /**
     * 功能描述: StreamAPI- 演示（元素去重）
     *              distinct() 集合元素去重
     *              collect() 集合转换-> 如数组转为Set
     *              Collectors.toSet()、生成一个Set集合
     *              forEach() 遍历集合
     * @methodName: seven
     * @params: []
     * @return: void
     * @exception:
     * @auther: WangYG
     * @date: 2020-02-23 00:29:17
     */
    public void seven(){

        //distinct 去重
        Integer[] repeat = {7,2,4,9,5,2,1,4};
        Stream.of(repeat)
                .distinct()
                .forEach(System.out::println);

        //数组转换为set [并自动去重]
        Set<Integer> set = Stream.of(repeat).collect(Collectors.toSet());
        System.out.println(set);
    }

    /**
     * 功能描述: StreamAPI- 演示（使用skip和limit模拟分页效果）
     *
     *              skip() 表示跳过多少个，即去掉多少个
     *              limit() 表示上限或范围，即选取多少个
     *
     * @methodName: eight
     * @params: []
     * @return: void
     * @exception:
     * @auther: WangYG
     * @date: 2020-02-23 00:44:33
     */
    public void eight(){

        //模拟分页，有50个元素，每10个一页
        //skip(num):表示跳过多少个，即去掉多少个。 limit(num):表示上限或范围，即选取多少个。

        //Stream.iterate(1, x -> x + 1).limit(50) 模拟生成50个元素
        List<Integer> pageList = Stream.iterate(1, x -> x + 1).limit(50)
                //使用排序sorted  a - b大于0 按正序排列，小的在前。
                .sorted((a, b) -> a - b)
                //skip跳过0个，limit选取10个，即[1~10]
                .skip(0).limit(10)

                //skip跳过10个，limit选取10个，即[11~20]
                //.skip(10).limit(10)

                //skip跳过20个，limit选取10个，即[21~30]
                //.skip(20).limit(10)

                //skip跳过30个，limit选取10个，即[31~40]
                //.skip(30).limit(10)

                //skip跳过40个，limit选取10个，即[41~50]
                //.skip(40).limit(10)

                //将元素收集到List集合中
                .collect(Collectors.toList());

        System.out.println(pageList);

    }

    /**
     * 功能描述: StreamAPI- 演示（使用Map()集合元素转换）
     *          将集合元素，转换为自定义对象Person类元素。
     *
     *              map() 将集合元素转换为其它类型的元素
     *              mapToInt() 将集合元素转换为Integer类型的元素
     *              sum() IntStream.sum() 求集合元素的和
     *              collect() 将转换的元素收集/转成指定的集合(List、Set等)
     *              forEach() 遍历集合
     *
     * @methodName: nine
     * @params: []
     * @return: void
     * @exception:
     * @auther: WangYG
     * @date: 2020-02-23 01:10:46
     */
    public void nine(){

        //将字符串数组，转为整数，并求和
        String[] strArray = {"5","10","20","30","40","50"};
        String numStr = "5,10,20,30,40,50";
        String names = "java,tomcat,jetty,dubbo,springBoot,springCloud";

        int sum = Stream.of(strArray).map(Integer::valueOf).mapToInt(x -> x).sum();
        System.out.println("sum : " + sum);
        int sum1 = Stream.of(strArray).mapToInt(Integer::valueOf).sum();
        System.out.println("sum1 : " + sum1);
        List<Integer> list = Stream.of(numStr.split(",")).map(x -> Integer.valueOf(x)).collect(Collectors.toList());
        System.out.println("list : " + list);
        int sum2 = Stream.of(numStr.split(",")).mapToInt(Integer::valueOf).sum();
        System.out.println("sum2 : " + sum2);

        //将names转换为Person类
        //将names按照逗号分隔成数组，然后Stream.of转换为Stream
        Stream.of(names.split(","))
                //将字符串name的Stream集合转换为Person()对象集合
                .map(x -> new Person(x))
                //将转换后的结果，收集成List集合
                .collect(Collectors.toList())
                //遍历收集好的List集合
                .forEach(obj -> System.out.println(obj));

        //使用Lambda-方法引用-重写一次
        Stream.of(names.split(","))
                .map(Person::new)
                .collect(Collectors.toList())
                .forEach(System.out::println);

    }

    /**
     *
     * 功能描述: StreamAPI- 演示（peek()-Stream操作中间使用peek灵活处理业务的演示）
     *          将集合元素，转换为自定义对象Person类元素。
     *
     *              peek() Stream操作中间使用peek灵活处理业务
     *              Stream<T> peek(Consumer<? super T> action); -> Consumer只由于消费参数对象
     *                  --public interface Consumer<T>
     *                      -- void accept(T t);
     *
     * @methodName: ten
     * @params: []
     * @return: void
     * @exception:
     * @auther: WangYG
     * @date: 2020-02-23 01:24:18
     */
    public void ten(){

        String numStr = "5,10,20,30,40,50";
        String names = "java,tomcat,jetty,dubbo,springBoot,springCloud";

        //1.元素求和
        //操作基本类型，使用peek()处理中间业务，类似于记录日志
        //Stream<T> peek(Consumer<? super T> action); -> Consumer只由于消费参数对象
        int sum = Stream.of(numStr.split(","))
                //此处使用peek()输出一下转换后的元素，类似于记录日志。
                .peek(System.out::println)
                .mapToInt(Integer::valueOf)
                .sum();
        System.out.println("sum : " + sum);

        //2. 元素转为自定义对象
        //操作自定义对象类型，使用peek()处理中间业务。
        Stream.of(names.split(","))
                .map(Person::new)
                //此处使用peek()，修改了对象中的name属性，起到中间处理业务的作用！
                .peek(x -> x.setName(x.getName()+"_中间修改名称"))
                .collect(Collectors.toList())
                .forEach(System.out::println);

    }

}

class Person{

    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}
